# Copyright (c) 2007, Enrico Franchi
# All rights reserved.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
#     * Redistributions of source code must retain the above copyright
#       notice, this list of conditions and the following disclaimer.
#     * Redistributions in binary form must reproduce the above copyright
#       notice, this list of conditions and the following disclaimer in the
#       documentation and/or other materials provided with the distribution.
#     * Neither the name of the University of California, Berkeley nor the
#       names of its contributors may be used to endorse or promote products
#       derived from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

import os

__all__ = (
    'fdreadline',
    'set_buffersize',    
    'get_buffersize'
)

size = 4
buffers = {}

def set_buffersize(sz):
    global size
    size = sz
    
def get_buffersize():
    global size
    return size

class EOF(Exception):
    pass

def fditerator(fd, fread=os.read):
    'Returns an iterator that yields all the lines obtained via fdreadline.'
    try:
        while True:
            yield fdreadline(fd, fread)
    except EOF:
        raise StopIteration

def fdreadline(fd, fread=os.read):
    """Reads a \\n terminated line from the file descriptor.
    
    The terminator is not returned. On EOF, raises EOF.
    """
    buf = buffers.get(fd, '')
    pos = buf.find('\n')
    if pos >=0:
        ret = buf[:pos]
        buffers[fd] = buf[pos+1:]
        return ret
    temp = fread(fd, size)
    while len(temp) > 0:
        l = temp.split('\n', 1)
        if len(l) == 1: # no \n
            buf += l[0]
            temp = fread(fd, size)
        else:
            ret = buf + l[0]
            buffers[fd] = l[1]
            return ret
    if len(buf)>0: 
        buffers[fd] = ''
        return buf
    else:
        try:
            del buffers[fd]
        except KeyError: pass
        raise EOF
    
if __name__ == '__main__':
    f  = open(__file__)
    fd = f.fileno()
    try:
        while True:
            s = fdreadline(fd)
            print s
    except EOF: pass
    f.close()
        
    f  = open(__file__)
    fd = f.fileno()
    i = fditerator(fd)
    for line in i:
        print line
    f.close()
    